package com.adcc.ags.cgw.service;

import com.adcc.ags.cgw.configuration.UserListFactory;
import com.adcc.ags.cgw.entity.msg.CGWMsg;
import com.adcc.ags.cgw.entity.msg.MsgType;
import com.adcc.ags.cgw.entity.user.*;
import com.adcc.ags.cgw.managed.proxy.MsgProxy;
import com.adcc.ags.cgw.utils.Constant;
import com.adcc.utility.log.Log;
import com.adcc.utility.msg620.ACARS620Msg;
import com.adcc.utility.msg620.ACARS620Parser;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import jersey.repackaged.com.google.common.collect.Sets;

import java.util.*;
import java.util.regex.Pattern;

/**
 * 消息路由服务接口实现类
 */
public class MsgRouterServiceImpl extends MsgRouterService {

    /**
     * 将路由规则转化为正则表达式
     * @param route
     * @return
     */
    private String formatRouteToRegex(String... route){
        String strRegex = Strings.nullToEmpty("");
        if(route != null && route.length > 0){
            for(int i=0; i< route.length; i++){
                if(i == route.length -1){
                    strRegex += route[i].replace(Constant.CHAR_USER_ROUTE,Constant.CHAR_USER_REGEX);
                }else{
                    strRegex += route[i].replace(Constant.CHAR_USER_ROUTE,Constant.CHAR_USER_REGEX) + "|";
                }
            }
        }
        return strRegex;
    }

    /**
     * 查找用户ID
     * @param dest
     * @return
     */
    private String findUserID(Set<String> dest,MsgType type){
        String strUsers = Strings.nullToEmpty("");
        if(dest != null && dest.size() > 0){
            for(Iterator<String> iterator = dest.iterator();iterator.hasNext();){
                String strDest = iterator.next();
                for(User user : UserListFactory.getInstance().getUserList()){
                    if(strDest.equals(user.getRecvQueue())){
                        strUsers += user.getId() + ",";
                        break;
                    }
                }
            }
        }
        if(type == MsgType.Uplink){
            strUsers = "1," + strUsers;
        }
        if (strUsers.endsWith(",")) {
            strUsers = strUsers.substring(0, strUsers.length() - 1);
        }
        return strUsers;
    }

    @Override
    protected boolean matchRoute(String element, String... route) {
        String strRegex = formatRouteToRegex(route);
        return Pattern.matches(strRegex,element);
    }

    @Override
    protected boolean matchRoute(String[] element, String... route) {
        String strRegex = formatRouteToRegex(route);
        for(String elt : element){
            if(Pattern.matches(strRegex,elt)){
                return true;
            }
        }
        return false;
    }

    @Override
    protected boolean matchRoute(String element, int start, String route) {
        String strRegex = formatRouteToRegex(route);
        return Pattern.compile(strRegex).matcher(element).find(start);
    }

    @Override
    protected Set<String> findDownlinkRoute(CGWMsg msg) {
        try{
            Set<String> dest = Sets.newHashSet();
            List<User> userList = UserListFactory.getInstance().getUserList();
            for(User user : userList){

                // 如果用户配置为全部转发，则下行报文不匹配路由直接发送
                if(user.isDownlinkForward()){
                    dest.add(user.getRecvQueue());
                }else{
                    if(user.getRouteList().size() > 0){
                        byte[] buffer = msg.getContent().getContent();
                        Optional<ACARS620Msg> optional = ACARS620Parser.parse(new String(buffer, 0, buffer.length));
                        if(optional.isPresent()){
                            for(Route route : user.getRouteList()){
                                if(route.getType() == RouteType.Downlink){
                                    boolean flag = true;
                                    DownlinkRoute dr = (DownlinkRoute)route;

                                    // 匹配接收地址
                                    if(dr.getRecvAddress() != null && dr.getRecvAddress().length > 0){
                                        flag = matchRoute(optional.get().getRecvAddress(),dr.getRecvAddress());
                                    }

                                    // 匹配发送地址
                                    if(!Strings.isNullOrEmpty(dr.getSendAddress())){
                                        flag = flag & matchRoute(optional.get().getSendAddress(),dr.getSendAddress());
                                    }

                                    // 匹配报文类型
                                    if(dr.getSmi() != null && dr.getSmi().length > 0){
                                        flag = flag & matchRoute(optional.get().getSmi(),dr.getSmi());
                                    }

                                    // 匹配航班号
                                    if(dr.getFi() != null && dr.getFi().length > 0){
                                        flag = flag & matchRoute(optional.get().getFi(),dr.getFi());
                                    }

                                    // 匹配机尾号
                                    if(dr.getAn() != null && dr.getAn().length > 0){
                                        flag = flag & matchRoute(optional.get().getAn(),dr.getAn());
                                    }

                                    // 匹配RGS站
                                    if(dr.getRgs() != null && dr.getRgs().length > 0){
                                        flag = flag & matchRoute(optional.get().getRgs(),dr.getRgs());

                                    }

                                    // 匹配关键字
                                    if(dr.getSpecLabel() != null && !Strings.isNullOrEmpty(dr.getSpecLabel().getContent()) && dr.getSpecLabel().getIndex() >=0) {
                                        flag = flag & matchRoute(optional.get().getFreeText(), dr.getSpecLabel().getIndex(), dr.getSpecLabel().getContent());
                                    }

                                    if(flag){
                                        dest.add(user.getRecvQueue());
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return dest;
        }catch (Exception ex){
            Log.error(MsgRouterService.class.getName(), "findDownlinkRoute() error",ex);
            return null;
        }
    }

    @Override
    protected Set<String> findUplinkRoute(CGWMsg msg, User user) {
        try{
            Set<String> dest = Sets.newHashSet();
            User targetUser = null;
            if (msg.getSender().equals(user.getId())) {
                targetUser = user;
            } else {
                List<User> userList = UserListFactory.getInstance().getUserList();
                for (User temp : userList) {
                    if (msg.getSender().equals(temp.getId())) {
                        targetUser = temp;
                        break;
                    }
                }
            }
            if(targetUser!= null && targetUser.getRouteList().size() > 0){
                byte[] buffer = msg.getContent().getContent();
                Optional<ACARS620Msg> optional = ACARS620Parser.parse(new String(buffer, 0, buffer.length));
                if (optional.isPresent()) {
                    for(Route route : targetUser.getRouteList()){
                        if(route.getType() == RouteType.Uplink){
                            boolean flag = true;
                            UplinkRoute ur = (UplinkRoute)route;

                            // 匹配接收地址
                            if(ur.getRecvAddress() != null && ur.getRecvAddress().length > 0){
                                flag = matchRoute(optional.get().getRecvAddress(),ur.getRecvAddress());
                            }

                            // 匹配发送地址
                            if(!Strings.isNullOrEmpty(ur.getSendAddress())){
                                flag = flag & matchRoute(optional.get().getSendAddress(),ur.getSendAddress());
                            }

                            // 匹配报文类型
                            if(ur.getSmi() != null && ur.getSmi().length > 0){
                                flag = flag & matchRoute(optional.get().getSmi(),ur.getSmi());
                            }

                            // 匹配机尾号
                            if(ur.getAn() != null && ur.getAn().length > 0){
                                flag = flag & matchRoute(optional.get().getAn(),ur.getAn());
                            }

                            // 匹配关键字
                            if(ur.getSpecLabel() != null && !Strings.isNullOrEmpty(ur.getSpecLabel().getContent()) && ur.getSpecLabel().getIndex() >=0) {
                                flag = flag & matchRoute(optional.get().getFreeText(), ur.getSpecLabel().getIndex(), ur.getSpecLabel().getContent());
                            }

                            if(flag){
                                if(ur.getDestination() != null && ur.getDestination().length > 0){
                                    for(String strDest : ur.getDestination()){
                                        dest.add(strDest);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return dest;
        } catch (Exception ex) {
            Log.error(MsgRouterService.class.getName(), "findUplinkRoute() error",ex);
            return null;
        }
    }

    @Override
    protected Set<String> findGroundRoute(CGWMsg msg, User user) {
        try {
            Set<String> dest = Sets.newHashSet();
            User targetUser = null;
            if (msg.getSender().equals(user.getId())) {
                targetUser = user;
            } else {
                List<User> userList = UserListFactory.getInstance().getUserList();
                for (User temp : userList) {
                    if (msg.getSender().equals(temp.getId())) {
                        targetUser = temp;
                        break;
                    }
                }
            }
            if(targetUser!= null && targetUser.getRouteList().size() > 0) {
                byte[] buffer = msg.getContent().getContent();
                String strMsg = new String(buffer, 0, buffer.length);
                for(Route route : targetUser.getRouteList()) {
                    if(route.getType() == RouteType.Ground) {
                        boolean flag = true;
                        GroundRoute gr = (GroundRoute) route;

                        // 匹配关键字
                        if(gr.getSpecLabel() != null && !Strings.isNullOrEmpty(gr.getSpecLabel().getContent()) && gr.getSpecLabel().getIndex() >=0) {
                            flag = matchRoute(strMsg, gr.getSpecLabel().getIndex(), gr.getSpecLabel().getContent());
                        }

                        if(flag) {
                            if (gr.getDestination() != null && gr.getDestination().length > 0) {
                                for (String strDest : gr.getDestination()) {
                                    dest.add(strDest);
                                }
                            }
                        }
                    }
                }
            }
            return dest;
        } catch (Exception ex) {
            Log.error(MsgRouterService.class.getName(), "findGroundRoute() error", ex);
            return null;
        }
    }

    @Override
    public void onReceive(Object message) {
        super.onReceive(message);
        try{

            // 如果消息类型为CGWMsg，则进行下行路由处理，消息类型为HashMap，则进行上行路由或地地处理，否则消息丢弃
            if(message instanceof CGWMsg){
                CGWMsg cgwMsg = (CGWMsg)message;

                // 下行报文路由处理
                Set<String> destSet = findDownlinkRoute(cgwMsg);
                if(destSet != null && destSet.size() > 0){
                    cgwMsg.setDestination(destSet);
                    String strReceiver = findUserID(destSet,cgwMsg.getType());
                    cgwMsg.setReceiver(strReceiver);
                    MsgProxy.getInstance().getMsgSendActor().tell(cgwMsg,this.getSelf());
                    saveMsg(cgwMsg);
                }else {
                    Log.error(MsgRouterService.class.getName(), "not find destination user downlink message:\r\n" + cgwMsg.getContent().toString());
                    saveMsg(cgwMsg,"F","",Constant.STRING_ERROR_CODE_ROUTEFAILED);
                }
            } else if(message instanceof Map) {

                Map<String, Object> map = (HashMap<String, Object>) message;
                if (map.containsKey(Constant.STRING_ROUTER_ACTOR_KEY1) && map.containsKey(Constant.STRING_ROUTER_ACTOR_KEY2)) {

                    // 获取CGWMsg
                    CGWMsg cgwMsg = (CGWMsg) map.get(Constant.STRING_ROUTER_ACTOR_KEY1);

                    // 获取User
                    User user = (User) map.get(Constant.STRING_ROUTER_ACTOR_KEY2);

                    // 根据报文标识处理上行和地地报文
                    if (MsgType.Uplink == cgwMsg.getType()) {
                        cgwMsg.setDestination(findUplinkRoute(cgwMsg, user));
                        String strReceiver = findUserID(cgwMsg.getDestination(),cgwMsg.getType());
                        cgwMsg.setReceiver(strReceiver);
                        MsgProxy.getInstance().getMsgSendActor().tell(cgwMsg, this.getSelf());
                        saveMsg(cgwMsg);
                    } else if (MsgType.Ground == cgwMsg.getType()) {
                        Set<String> destSet = findGroundRoute(cgwMsg, user);
                        if (destSet != null && destSet.size() > 0) {
                            cgwMsg.setDestination(destSet);
                            String strReceiver = findUserID(destSet,cgwMsg.getType());
                            cgwMsg.setReceiver(strReceiver);
                            MsgProxy.getInstance().getMsgSendActor().tell(cgwMsg, this.getSelf());
                            saveMsg(cgwMsg);
                        } else {
                            Log.error(MsgRouterService.class.getName(), "not find destination user ground message:\r\n" + cgwMsg.getContent().toString());
                            saveMsg(cgwMsg,"F","",Constant.STRING_ERROR_CODE_ROUTEFAILED);
                        }
                    }
                } else {
                    unhandled(message);
                }
            } else {
                Log.error(MsgRouterService.class.getName(),"receive invalid message");
                unhandled(message);
            }
        }catch (Exception ex){
            Log.error(MsgRouterService.class.getName(),"onReceive() error",ex);
        }
    }
}
